package com.yunhe.common.aspect;

import com.alibaba.fastjson.JSON;
import com.yunhe.common.annotation.CodeFromTitle;
import com.yunhe.common.tempcache.CacheMap;
import com.yunhe.common.util.CollectionUtil;
import com.yunhe.common.util.RedisClient;
import com.yunhe.common.util.ReflectUtil;
import com.yunhe.common.util.StringUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: DongWenYu
 * @Date: 2021/6/4 16:39
 */
@Component
@Aspect
public class CodeFromTitleAspect extends HandlerInterceptorAdapter {

    @Autowired
    private RedisClient redisClient;

    private CacheMap<String,String> itemMap = CacheMap.getDefault();

    private static final Logger logger = LoggerFactory.getLogger(CodeFromTitle.class);

    @Pointcut("execution(* com.yunhe..repository.*Repository.insertBatch(..))")
    public void pointCutInsert() {
    }
    @Pointcut("execution(* com.yunhe..repository.*Repository.updateBatchById(..))")
    public void pointCutUpdate() {
    }

    @Before("pointCutInsert()")
    public Object enumItemCodeTranslator(JoinPoint pjp) throws Throwable {
        Object[] result = pjp.getArgs();
        logger.info("进入CodeFromTitleAspect,resultCount:{}", Arrays.stream(result).count());
        for (int i = 0 ; i<result.length ; i ++) {
            this.translator(result[i]);
        }
        return result;
    }

    private void translator(Object obj) throws Exception {
        //List类型
        if (obj instanceof List) {
            List<?> list=(List<?>)obj;
            for (Object object : list) {
                if (object != null && !(object.getClass().equals(String.class) || (object.getClass().equals(Integer.class)))) {
                    dealAnnotationsInsideMethod(object);
                }
            }
            logger.info("dealAnnotationsInsideMethod结束,listSize:{}",list.size());
        }
        //其他类型：Vo,Map
        else {
            dealAnnotationsInsideMethod(obj);
        }
    }

    private void dealAnnotationsInsideMethod(Object obj) throws Exception {
        Class<?> clazz = obj.getClass();
        while (!Object.class.equals(clazz)) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                //出参设置标准代码
                //标准代码名称属性
                if (field.isAnnotationPresent(CodeFromTitle.class)) {
                    String code = field.getAnnotation(CodeFromTitle.class).code();
                    String fieldNoTitle = field.getAnnotation(CodeFromTitle.class).fieldTitle();
                    if (StringUtil.isBlank(fieldNoTitle)) {
                        fieldNoTitle = field.getName()+"Title";
                    }
                    ReflectionUtils.makeAccessible(field);
                    Method getMethod = null;
                    String methodName = ReflectUtil.getMethodName(fieldNoTitle);//获得get方法
                    String fieldValue = null;
                    try {
                        getMethod = clazz.getMethod(methodName);
                        fieldValue = getMethod.invoke(obj, new Object[]{}) + "";
                    } catch (Exception e) {
                        throw new Exception("没有" + fieldNoTitle + "的属性!");
                    }

                    if ("null".equals(fieldValue)) {
                        String noTitleMethodName = ReflectUtil.getMethodName(field.getName());//获得code的get方法
                        try {
                            Method getNoTitleMethod = clazz.getMethod(noTitleMethodName);
                            String fieldNoTitleValue = getNoTitleMethod.invoke(obj, new Object[]{}) + "";
                            if (!"null".equals(fieldNoTitleValue)){
                                field.set(obj, fieldNoTitleValue);
                            }else {
                                field.set(obj,null);
                            }
                        } catch (Exception e) {
                            throw new Exception("没有" + field.getName() + "的属性!");
                        }
                        continue;
                    }
                    String fieldValueString = null;
                    try {
                        fieldValueString = (String) fieldValue;
                    } catch (ClassCastException e) {
                        throw new Exception("必须注解到String类型!");
                    }
                    String enumItems = itemMap.get(code);
                    if(StringUtil.isEmpty(enumItems)){
                        enumItems = redisClient.get("ENUM_ITEM:"+code);
                        itemMap.put(code,enumItems);
                    }
                    //String enumItems = redisClient.get("ENUM_ITEM:"+code);
                    if(!StringUtil.isEmpty(enumItems)){
                        List<Map<String,Object>> maps = (List<Map<String, Object>>) JSON.parse(enumItems);
                        if(!CollectionUtil.isEmpty(maps)){
                            for (Map<String, Object> map : maps) {
                                Object titleObj = map.get("title");
                                Object codeObj = map.get("code");
                                //用"/"分隔为同一个code不同title
                                if (titleObj.toString().contains("/")){
                                    String[] split = titleObj.toString().split("/");
                                    for (String s :split){
                                        if(s.equals(fieldValueString)) {
                                            fieldValueString = codeObj.toString();
                                        }
                                    }
                                }else {
                                    String finalFieldValueString = fieldValueString;
                                    List<Map<String, Object>> mapList = maps.stream().filter(map1 -> {
                                        return finalFieldValueString.equals(map1.get("title"));
                                    }).collect(Collectors.toList());

                                    if(CollectionUtil.isEmpty(mapList)){
                                        for (Map<String, Object> map1 : maps) {
                                            Object titleObj1 = map1.get("title");
                                            Object codeObj1 = map1.get("code");
                                            if(StringUtil.containsIgnoreCase(titleObj1.toString(),fieldValueString)){
                                                fieldValueString = codeObj1.toString();
                                            }else if(fieldValueString.contains(titleObj1.toString())){
                                                fieldValueString = fieldValueString.replace(titleObj1.toString(),codeObj1.toString());
                                            }
                                        }
                                    }else {
                                        Object titleObj1 = mapList.get(0).get("title");
                                        Object codeObj1 = mapList.get(0).get("code");
                                        fieldValueString = fieldValueString.replace(titleObj1.toString(),codeObj1.toString());
                                    }
                                    field.set(obj,fieldValueString);
                                }
                            }
                        }
                        if (!"null".equals(fieldValueString)){
                            field.set(obj, fieldValueString);
                        }else {
                            field.set(obj,null);
                        }
                    }

                }

            }
            clazz = clazz.getSuperclass();
        }
    }

}


